/*
 * Copyright 2010 Cedric Priscal
 *
 * This file is part of stupid-avr-robot.
 *
 * stupid-avr-robot is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * stupid-avr-robot is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with stupid-avr-robot.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "LinuxSerialPort.h"

#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

LinuxSerialPort::LinuxSerialPort() : Usart() {
	mFd = -1;
}

void LinuxSerialPort::tryopen() {
    // Open and configure serial port in NON-BLOCKING MODE for configuration
	mFd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);

	if (mFd != -1) {
		struct termios termios_p;
		if (tcgetattr(mFd, &termios_p)) {
			perror("tcgetattr failed");
			close(mFd);
			mFd = -1;
			return;
		}
		cfmakeraw(&termios_p);
        termios_p.c_cflag |= CLOCAL;
		if (cfsetspeed(&termios_p, B115200) || tcsetattr(mFd, TCSANOW, &termios_p)) {
			perror("cfsetspeed or tcsetattr failed");
			close(mFd);
			mFd = -1;
			return;
		}

        // Reopen port with BLOCKING MODE activated
        close(mFd);
        mFd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
        // Read configuration again just for debug
		if (tcgetattr(mFd, &termios_p)) {
			perror("tcgetattr failed");
			close(mFd);
			mFd = -1;
			return;
		}

		// Start port reading thread
		start();
	} else {
		perror("Cannot open port!");
		exit(1);
	}
}

void LinuxSerialPort::send(unsigned char c) {
	if (mFd == -1) {
		tryopen();
	}
	if (mFd != -1) {
		if (write(mFd, &c, sizeof(unsigned char)) == sizeof(unsigned char)) {
		} else {
			fprintf(stderr, "[Cannot write to serial port!]");
			close(mFd);
			mFd = -1;
		}
	}
}

void LinuxSerialPort::run() {
	for(;;) {
		unsigned char incoming;
		int size = read(mFd, &incoming, sizeof(incoming));
		if (size == sizeof(incoming)) {
			if (mListener) {
				mListener->onUsartReceived(incoming);
			}
		} else {
			close(mFd);
			mFd = -1;
			return;
		}
	}
}
